<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 Exception handling in C and in Objective CAML
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora116.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora118.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> Exception handling in C and in Objective CAML</H2>
<A NAME="@concepts278"></A>
Different languages have different mechanisms for raising and handling
exceptions: C relies on <TT>setjmp</TT> and <TT>longjmp</TT>, while
Objective CAML has built-in constructs for exceptions (<B>try ... with</B>,
<B>raise</B>). Of course, these mechanisms are not compatible:
they do not keep the same information when setting up a handler.
It is extremely hard to safely implement the nesting of exception
handlers of different kinds, while ensuring that an exception
correctly ``jumps over'' handlers. For this reason, only Objective CAML
exceptions can be raised and handled from C; <TT>setjmp</TT> and
<TT>longjmp</TT> in C cannot be caught from Objective CAML, and must not
be used to skip over Objective CAML code.<BR>
<BR>
All functions and macros introduced in this section are defined in the
header file <TT>fail.h</TT>.<BR>
<BR>
<A NAME="toc159"></A>
<H3> Raising a predefined exception</H3>
From a C function, it is easy to raise one of the exceptions
<TT>Failure</TT>, <TT>Invalid_argument</TT> or <TT>Not_found</TT> 
from the <TT>Pervasives</TT> module: just use the following functions.
<DIV ALIGN=center>
<TABLE CELLSPACING=2 CELLPADDING=0>
<TR><TD  ALIGN=left NOWRAP><TT>failwith(s)</TT></TD>
<TD  ALIGN=center NOWRAP>:</TD>
<TD  ALIGN=left NOWRAP>raise the exception <EM>Failure(s)</EM></TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>invalid_argument(s)</TT></TD>
<TD  ALIGN=center NOWRAP>:</TD>
<TD  ALIGN=left NOWRAP>raise the exception
<EM>Invalid_argument(s)</EM></TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>raise_not_found()</TT></TD>
<TD  ALIGN=center NOWRAP>:</TD>
<TD  ALIGN=left NOWRAP>raise the exception
<EM>Not_found</EM></TD>
</TR></TABLE>
</DIV>
In the first two cases, <TT>s</TT> is a C string (<TT>char *</TT>) that ends up as the argument to the exception raised.<BR>
<BR>
<A NAME="toc160"></A>
<H3> Raising a user-defined exception</H3>
A registration mechanism similar to that for closures enables
user-defined exceptions to be raised from C. We must first register the exception
using the <TT>Callback</TT> module's <TT>register_exception</TT> function.
Then, from C, we retrieve the exception identifier
using the <TT>caml_named_value</TT> function (see page
<A HREF="book-ora116.html#subsec-register">??</A>). Finally, we raise the exception, using one
of the following functions:
<DIV ALIGN=center>
<TABLE CELLSPACING=2 CELLPADDING=0>
<TR><TD  ALIGN=left NOWRAP><TT>raise_constant(e)</TT></TD>
<TD  ALIGN=left NOWRAP>raise the exception <TT>e</TT> with no argument,</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>raise_with_arg(e,v)</TT></TD>
<TD  ALIGN=left NOWRAP>raise the exception <TT>e</TT> with the
value <TT>v</TT> as argument,</TD>
</TR>
<TR><TD  ALIGN=left NOWRAP><TT>raise_with_string(e,s)</TT></TD>
<TD  ALIGN=left NOWRAP>same, but the argument is taken from
the C string <TT>s</TT>.</TD>
</TR></TABLE>
</DIV><BR>
Here is an example C function that raises an Objective CAML exception:<BR>
<BR>


<PRE>
<CODE>#include &lt;caml/mlvalues.h&gt;</CODE><BR><CODE>#include &lt;caml/memory.h&gt;</CODE><BR><CODE>#include &lt;caml/fail.h&gt;</CODE><BR><BR><CODE>value divide (value v1,value v2) </CODE><BR><CODE>{ </CODE><BR><CODE>  CAMLparam2(v1,v2);</CODE><BR><CODE>  if (Long_val(v2) == 0) </CODE><BR><CODE>    raise_with_arg(*caml_named_value("divzero"),v1) ;</CODE><BR><CODE>  CAMLreturn Val_long(Long_val(v1)/Long_val(v2)) ;</CODE><BR><CODE>}</CODE><BR>

</PRE>
<BR>
<BR>
And here is an Objective CAML transcript showing the use of that C function:<BR>
<BR>


<PRE><BR># <B>external</B><CODE> </CODE>divide<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE> </CODE>-&gt;<CODE> </CODE>int<CODE> </CODE>-&gt;<CODE> </CODE>int<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"divide"</CODE><CODE> </CODE>;;<BR><CODE>external divide : int -&gt; int -&gt; int = "divide"</CODE><BR># <B>exception</B><CODE> </CODE>Division_zero<CODE> </CODE><B>of</B><CODE> </CODE>int<CODE> </CODE>;;<BR><CODE>exception Division_zero of int</CODE><BR># Callback.register_exception<CODE> </CODE><CODE>"divzero"</CODE><CODE> </CODE><TT>(</TT>Division_zero<CODE> </CODE><CODE>0</CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>- : unit = ()</CODE><BR># divide<CODE> </CODE><CODE>2</CODE><CODE>0</CODE><CODE> </CODE><CODE>4</CODE><CODE> </CODE>;;<BR><CODE>- : int = 5</CODE><BR># divide<CODE> </CODE><CODE>2</CODE><CODE>2</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>;;<BR><CODE>Uncaught exception: Division_zero(22)</CODE><BR>

</PRE>
<BR>
<BR>
<A NAME="toc161"></A>
<H3> Catching an exception</H3>
In a C function, we cannot catch an exception raised from
another C function.
However, we can catch Objective CAML exceptions arising from the
application of an Objective CAML function (callback).
This is achieved
via the functions <TT>callback_exn</TT>, <TT>callback2_exn</TT>, <TT>callback3_exn</TT> and <TT>callbackN_exn</TT>, which are similar to the
standard <TT>callback</TT> functions, except that if the callback raises
an exception, this exception is caught and returned as the result of
the callback. The result value of the <TT>callback_exn</TT> functions
must be tested with <TT>Is_exception_result(v)</TT>; this predicate
returns ``true'' if the result value represents an uncaught exception,
and ``false'' otherwise. The macro <TT>Extract_exception(v)</TT>
returns the exception value contained in an exceptional result value.<BR>
<BR>
The C function <TT>divide_print</TT> below calls the Objective CAML function
<TT>divide</TT> using <TT>callback2_exn</TT>, and checks whether the
result is an exception. If so, it prints a message and raises the
exception again; otherwise it prints the result.<BR>
<BR>


<PRE>
<CODE>#include &lt;stdio.h&gt;</CODE><BR><CODE>#include &lt;caml/mlvalues.h&gt;</CODE><BR><CODE>#include &lt;caml/memory.h&gt;</CODE><BR><CODE>#include &lt;caml/callback.h&gt;</CODE><BR><CODE>#include &lt;caml/fail.h&gt;</CODE><BR><BR><CODE>value divide_print (value v1,value v2) </CODE><BR><CODE>{ </CODE><BR><CODE>  CAMLparam2(v1,v2) ;</CODE><BR><CODE>  CAMLlocal3(div,dbz,res) ;</CODE><BR><CODE>  div = * caml_named_value("divide") ;</CODE><BR><CODE>  dbz = * caml_named_value("div_by_0") ;</CODE><BR><CODE>  res = callback2_exn (div,v1,v2) ; </CODE><BR><CODE>  if (Is_exception_result(res)) </CODE><BR><CODE>    {</CODE><BR><CODE>      value exn=Extract_exception(res);</CODE><BR><CODE>      if (Field(exn,0)==dbz)  printf("division by 0\n") ;</CODE><BR><CODE>      else printf("other exception\n"); </CODE><BR><CODE>      fflush(stdout);</CODE><BR><CODE>      if (Wosize_val(exn)==1)  raise_constant(Field(exn,0)) ;</CODE><BR><CODE>      else raise_with_arg(Field(exn,0),Field(exn,1)) ;</CODE><BR><CODE>    }</CODE><BR><CODE>  printf("result = %d\n",Long_val(res)) ;</CODE><BR><CODE>  fflush(stdout) ;</CODE><BR><CODE>  CAMLreturn Val_unit ;</CODE><BR><CODE>}</CODE><BR>

</PRE>



<PRE><BR># Callback.register<CODE> </CODE><CODE>"divide"</CODE><CODE> </CODE><TT>(</TT><CODE>/</CODE><TT>)</TT><CODE> </CODE>;;<BR><CODE>- : unit = ()</CODE><BR># Callback.register_exception<CODE> </CODE><CODE>"div_by_0"</CODE><CODE> </CODE>Division_by_zero<CODE> </CODE>;;<BR><CODE>- : unit = ()</CODE><BR># <B>external</B><CODE> </CODE>divide_print<CODE> </CODE><CODE>:</CODE><CODE> </CODE>int<CODE> </CODE>-&gt;<CODE> </CODE>int<CODE> </CODE>-&gt;<CODE> </CODE>unit<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"divide_print"</CODE><CODE> </CODE>;;<BR><CODE>external divide_print : int -&gt; int -&gt; unit = "divide_print"</CODE><BR># divide_print<CODE> </CODE><CODE>4</CODE><CODE>2</CODE><CODE> </CODE><CODE>3</CODE><CODE> </CODE>;;<BR><CODE>result = 14</CODE><BR><CODE>- : unit = ()</CODE><BR># divide_print<CODE> </CODE><CODE>2</CODE><CODE>1</CODE><CODE> </CODE><CODE>0</CODE><CODE> </CODE>;;<BR><CODE>division by 0</CODE><BR><CODE>Uncaught exception: Division_by_zero</CODE><BR>

</PRE>
<BR>
<BR>
As the examples above show, it is possible to raise an exception from
C and catch it in Objective CAML, and also to raise an exception from
Objective CAML and catch it in C. However, a C program cannot by itself
raise and catch an Objective CAML exception.<BR>
<BR>
<HR>
<A HREF="book-ora116.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora118.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
